package org.wdcode.web.http;

import java.io.InputStream;
import java.util.List;
import java.util.Map;

import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.cookie.BasicClientCookie;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.protocol.HttpContext;

import org.wdcode.common.constants.EncodingConstants;
import org.wdcode.common.constants.StringConstants;
import org.wdcode.common.exception.CustomRuntimeException;
import org.wdcode.common.tools.Lists;
import org.wdcode.common.util.CommonUtil;

/**
 * 实现HTTP模拟浏览器提交的实现类
 * @author WD
 * @since JDK6
 * @version 1.0 2009-06-03
 */
final class HttpClientImpl extends DefaultHttpClient implements HttpClient {
	// 头 User-Agent 信息
	private final static String	USER_AGENT_KEY;
	private final static String	USER_AGENT_VAL;
	// 参数KEY
	private final static String	CONTENT_CHARSET;
	private final static String	COOKIE_HEADER;
	// 头 Accept 信息
	private final static String	ACCEPT_KEY;
	private final static String	ACCEPT_VAL;
	// 头Accept-Language信息
	private final static String	ACCEPT_LANGUAGE_KEY;
	private final static String	ACCEPT_LANGUAGE_VAL;
	// 头Accept-Charset信息
	private final static String	ACCEPT_CHARSET_KEY;
	private final static String	ACCEPT_CHARSET_VAL;
	// 头Content-Type信息
	private final static String	CONTENT_TYPE_KEY;
	private final static String	CONTENT_TYPE_VAL;
	// 头Referer
	private final static String	REFERER_KEY;
	// 当前URL
	private String				currentURL;
	// HttpContext
	private HttpContext			context;

	// 静态初始化
	static {
		ACCEPT_KEY = "Accept";
		ACCEPT_VAL = "text/xml,text/javascript,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
		// 头Accept-Language信息
		ACCEPT_LANGUAGE_KEY = "Accept-Language";
		ACCEPT_LANGUAGE_VAL = "en-us;q=0.7,en;q=0.3";
		// 头Accept-Charset信息
		ACCEPT_CHARSET_KEY = "Accept-Charset";
		ACCEPT_CHARSET_VAL = "ISO-8859-1,utf-8;q=0.7,*;q=0.7";
		// 头Content-Type信息
		CONTENT_TYPE_KEY = "Content-Type";
		CONTENT_TYPE_VAL = "application/x-www-form-urlencoded";
		// 头Referer
		REFERER_KEY = "Referer";
		USER_AGENT_KEY = "User-Agent";
		USER_AGENT_VAL = "Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13";
		CONTENT_CHARSET = "http.protocol.content-charset";
		COOKIE_HEADER = "http.protocol.single-cookie-header";
	}

	/**
	 * 构造方法
	 * @param encoding 编码
	 */
	public HttpClientImpl(String encoding) {
		// 父构造
		super();
		// 设置CookieStore对象
		setCookieStore(new BasicCookieStore());
		// 设置参数
		getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
		// 生成头列表
		List<Header> headers = Lists.getList();
		// 添加头信息
		headers.add(new BasicHeader(USER_AGENT_KEY, USER_AGENT_VAL));
		// 设置头参数
		getParams().setParameter(ClientPNames.DEFAULT_HEADERS, headers);
		// 设置编码
		getParams().setParameter(CONTENT_CHARSET, encoding);
		// 设置保存cookie头
		getParams().setParameter(COOKIE_HEADER, true);
		// 设置HttpContext
		setHttpContext();
	}

	/**
	 * 获得HttpContext的属性
	 * @param id 属性ID
	 * @return 获得的对象
	 */
	public Object getAttribute(String id) {
		return context.getAttribute(id);
	}

	/**
	 * 设置HttpContext
	 */
	public void setHttpContext() {
		context = createHttpContext();
	}

	/**
	 * 获得当前的URL
	 * @return URL地址
	 */
	public String getCurrentURL() {
		return currentURL;
	}

	/**
	 * 添加Cookie
	 * @param cookie Cookie对象
	 */
	public void addCookie(Cookie cookie) {
		getCookieStore().addCookie(cookie);
	}

	/**
	 * 添加Cookie
	 * @param name Cookie名
	 * @param value Cookie值
	 */
	public void addCookie(String name, String value) {
		addCookie(new BasicClientCookie(name, value));
	}

	/**
	 * 根据name获得Cookie
	 * @param name cookie名
	 * @return Cookie 如果没有找到返回null
	 */
	public Cookie getCookie(String name) {
		// 判断Cookie Name
		if (CommonUtil.isEmpty(name)) {
			return null;
		}
		// 获得Cookie列表
		List<Cookie> lsCookie = getCookies();
		// 声明Cookie
		Cookie cookie = null;

		// 循环Cookie
		for (int i = 0; i < lsCookie.size(); i++) {
			// 判断Cookie Name
			if (lsCookie.get(i).getName().equals(name)) {
				// 获得Cookie
				cookie = lsCookie.get(i);
				break;
			}
		}
		// 返回Cookie
		return cookie;
	}

	/**
	 * 根据name获得Cookie值
	 * @param name cookie名
	 * @return Cookie值 如果没有找到返回""
	 */
	public String getCookieValue(String name) {
		// 获得Cookie
		Cookie cookie = getCookie(name);
		// 返回值
		return CommonUtil.isEmpty(cookie) ? StringConstants.EMPTY : cookie.getValue();
	}

	/**
	 * 获得所有Cookie列表
	 * @return Cookie列表
	 */
	public List<Cookie> getCookies() {
		return getCookieStore().getCookies();
	}

	/**
	 * 设置连接超时
	 * @param value 毫秒数
	 */
	public void setTimeOut(long value) {
		getParams().setLongParameter(HttpConnectionParams.SO_TIMEOUT, value);
	}

	/**
	 * 关闭资源
	 */
	public void close() {
		// 关闭连接
		getConnectionManager().shutdown();
		// HttpContext = null
		context = null;
	}

	/**
	 * 模拟get提交
	 * @param url get提交地址
	 * @return InputStream 提交后的流
	 */
	public InputStream doGet(String url) {
		return doGet(url, null);
	}

	/**
	 * 模拟get提交
	 * @param url get提交地址
	 * @param referer referer地址
	 * @return InputStream 提交后的流
	 */
	public InputStream doGet(String url, String referer) {
		// 声明HttpGet对象
		HttpGet get = null;
		try {
			// 获得HttpGet对象
			get = new HttpGet(url);
			// 设置头信息
			setHeaders(get, referer);
			// 获得HttpResponse
			HttpResponse response = execute(get, context);
			// 更新Url
			updateCurrentUrl(get);
			// 判断状态
			if (response.getStatusLine().getStatusCode() == 302) {
				// 如果是302重定向 那么重新提交
				return doGet(getRedirectHandler().getLocationURI(response, context).toString(), referer);
			} else {
				// 其它状态返回流
				return response.getEntity().getContent();
			}
		} catch (Exception e) {
			throw new CustomRuntimeException();
		} finally {
			// 销毁get
			// get.abort();
			// 关闭连接
			getConnectionManager().closeExpiredConnections();
		}
	}

	/**
	 * 模拟post提交
	 * @param url post提交地址
	 * @param data 提交参数
	 * @param referer referer地址
	 * @param encoding 提交参数的编码格式
	 * @return InputStream 提交后的流
	 */
	public InputStream doPost(String url, Map<String, String> data, String referer, String encoding) {
		// 声明HttpPost
		HttpPost post = null;
		try {
			// 获得HttpPost
			post = new HttpPost(url);
			// 设置头信息
			setHeaders(post, referer);
			// 添加post Content-Type头
			post.addHeader(CONTENT_TYPE_KEY, CONTENT_TYPE_VAL);
			// 如果参数列表为空 data为空map
			if (!CommonUtil.isEmpty(data)) {
				// 声明参数列表
				List<NameValuePair> list = Lists.getList(data.size());
				// 设置参数
				for (Map.Entry<String, String> entry : data.entrySet()) {
					// 添加参数
					list.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
				}
				// 设置参数与 编码格式
				post.setEntity(new UrlEncodedFormEntity(list, encoding));
			}
			// 设置协议参数
			// HttpProtocolParams.setUseExpectContinue(getParams(), false);
			// HttpProtocolParams.setUseExpectContinue(post.getParams(), false);
			// 获得HttpResponse参数
			HttpResponse response = execute(post, context);
			// 更新Url
			updateCurrentUrl(post);
			// 判断状态
			if (response.getStatusLine().getStatusCode() == 302) {
				// 如果是302重定向 那么重新提交
				return doPost(getRedirectHandler().getLocationURI(response, context).toString(), data, referer);
			} else {
				// 其它状态返回流
				return response.getEntity().getContent();
			}
		} catch (Exception e) {
			throw new CustomRuntimeException();
		} finally {
			// 销毁post
			// post.abort();
			// 关闭连接
			getConnectionManager().closeExpiredConnections();
		}
	}

	/**
	 * 模拟post提交
	 * @param url post提交地址
	 * @param data 提交参数
	 * @param referer referer地址
	 * @return InputStream 提交后的流
	 */
	public InputStream doPost(String url, Map<String, String> data, String referer) {
		return doPost(url, data, referer, EncodingConstants.UTF_8);
	}

	/**
	 * 模拟post提交 默认使用UTF-8格式
	 * @param url post提交地址
	 * @param data 提交参数
	 * @return InputStream 提交后的流
	 */
	public InputStream doPost(String url, Map<String, String> data) {
		return doPost(url, data, null, EncodingConstants.UTF_8);
	}

	/**
	 * 设置头
	 * @param req
	 * @param referer
	 */
	private void setHeaders(HttpRequest req, String referer) {
		// 添加头信息
		req.addHeader(ACCEPT_KEY, ACCEPT_VAL);
		req.addHeader(ACCEPT_LANGUAGE_KEY, ACCEPT_LANGUAGE_VAL);
		req.addHeader(ACCEPT_CHARSET_KEY, ACCEPT_CHARSET_VAL);
		// 添加头Referer信息
		if (!CommonUtil.isEmpty(referer)) {
			req.addHeader(REFERER_KEY, referer);
		}
	}

	/*
	 * 更新当前Url
	 */
	private void updateCurrentUrl(HttpUriRequest request) {
		// 获得当前Url
		currentURL = request.getURI().toString();
	}

	/**
	 * 获得HttpContext
	 * @return
	 */
	// private HttpContext getDefaultContext() {
	// if (context == null) {
	// context = createHttpContext();
	// populateContext(context);
	// }
	// return context;
	// }
	/**
	 * 设置HttpContext
	 * @param context
	 */
	// private void populateContext(HttpContext context) {
	// context.setAttribute("http.authscheme-registry", getAuthSchemes());
	// context.setAttribute("http.cookiespec-registry", getCookieSpecs());
	// context.setAttribute("http.cookie-store", getCookieStore());
	// context.setAttribute("http.auth.credentials-provider",
	// getCredentialsProvider());
	// }
}
